#include "ScriptInteraction.h"
#include "URLUtilities.h"

const char CScriptInteraction::className[] = "HTTP";
const Luna<CScriptInteraction>::RegType CScriptInteraction::Register[] = {
	{ "Send", &CScriptInteraction::LuaSend },
	{ "Header", &CScriptInteraction::LuaHeader },
	{ "Server", &CScriptInteraction::LuaServerVariable },
	{ "Get", &CScriptInteraction::LuaGetVariable },
	{ "Post", &CScriptInteraction::LuaPostVariable },
	{ 0 }
};

CScriptInteraction::CScriptInteraction(Client *aClient, HTTPRequestInfo *aRequestInfo, HTTPResponseHeaders *aResponseHeaders)
{
	mClient = aClient;
	mRequestInfo = aRequestInfo;
	mResponseHeaders = aResponseHeaders;

	for(auto it = (*mRequestInfo).mHeaders.begin(); it != (*mRequestInfo).mHeaders.end(); ++it)
	{
		mVariables.push_back(*it);
		mVariables.back().first = "HTTP_" + mVariables.back().first;
	}
	string TempPostData = mRequestInfo->mPostData;
	size_t Pos = TempPostData.find("&");
	string Temp;
	if(TempPostData.length() > 0 && Pos == string::npos)
	{
		Pos = TempPostData.find("=");
		if(Pos != string::npos)
		{
			mPost.push_back(pair<string, string>(URLUtilities::Decode(TempPostData.substr(0, Pos), false), URLUtilities::Decode(TempPostData.substr(Pos+1), false)));
		}
	}
	else
	{
		while(Pos != string::npos)
		{
			Temp = TempPostData.substr(0, Pos);
			TempPostData = TempPostData.substr(Pos + 1);

			Pos = Temp.find("=");

			mPost.push_back(pair<string, string>(URLUtilities::Decode(Temp.substr(0, Pos)), URLUtilities::Decode(Temp.substr(Pos+1))));

			size_t Pos = TempPostData.find("&");
		}
	}

	string TempGetData = mRequestInfo->mQueryString;
	Pos = TempPostData.find("&");

	if(TempGetData.length() > 0 && Pos == string::npos)
	{
		Pos = TempGetData.find("=");
		if(Pos != string::npos)
		{
			mGet.push_back(pair<string, string>(URLUtilities::Decode(TempGetData.substr(0, Pos)), URLUtilities::Decode(TempGetData.substr(Pos+1))));
		}
	}
	else
	{
		while(Pos != string::npos)
		{
			Temp = TempPostData.substr(0, Pos);
			TempPostData = TempPostData.substr(Pos + 1);

			Pos = Temp.find("=");
			if(Pos != string::npos)
			{
				mGet.push_back(pair<string, string>(URLUtilities::Decode(Temp.substr(0, Pos)), URLUtilities::Decode(Temp.substr(Pos+1))));
				size_t Pos = TempPostData.find("&");
			}
		}
	}

	mVariables.push_back(pair<string, string>("SERVER_PROTOCOL", mRequestInfo->mVersion));
	mVariables.push_back(pair<string, string>("REQUEST_METHOD", mRequestInfo->mMethod));
	mVariables.push_back(pair<string, string>("REQUEST_URI", mRequestInfo->mResource));
	mVariables.push_back(pair<string, string>("QUERY_STRING", mRequestInfo->mQueryString));
	mVariables.push_back(pair<string, string>("POST_STRING", mRequestInfo->mPostData));
	mVariables.push_back(pair<string, string>("REMOTE_ADDR", (char*)mClient->mSocket->GetClientAddr()));
	//mVariables.push_back(pair<string, string>("", );
}
CScriptInteraction::CScriptInteraction(lua_State *L)
{

}


CScriptInteraction::~CScriptInteraction(void)
{
	mClient->Send("0\r\n\r\n");
}

int CScriptInteraction::LuaSend(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc == 2)
	{
		if(lua_isstring(L, 2))
		{
			string Temp = lua_tostring(L, 2);

			lua_pushnumber(L, Send(lua_tostring(L, 2)));
			return 1;
		}
		else
		{
			// ERROR HANDLE
			luaL_error(L, "Invalid Type");
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

int CScriptInteraction::LuaHeader(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc == 3)
	{
		if(lua_isstring(L, 2) && lua_isstring(L, 3))
		{
			lua_pushnumber(L, Header(lua_tostring(L, 2), lua_tostring(L, 3)));
			return 1;
		}
		else
		{
			// ERROR HANDLE
			luaL_error(L, "Invalid Type. String expected");
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

int CScriptInteraction::LuaGetVariable(lua_State *L)   
{
	int argc = lua_gettop(L);
	if(argc == 2)
	{
		if(lua_isstring(L, 2))
		{

			lua_pushstring(L, GetVariable(lua_tostring(L, 2)).c_str());
			return 1;
		}
		else
		{
			// ERROR HANDLE
			luaL_error(L, "Invalid type. String expected");
			return 1;
		}
	}
	else
	{
		return 0;
	}
}
int CScriptInteraction::LuaServerVariable(lua_State *L)
{
	int argc = lua_gettop(L);
	if(argc == 2)
	{
		if(lua_isstring(L, 2))
		{

			lua_pushstring(L, ServerVariable(lua_tostring(L, 2)).c_str());
			return 1;
		}
		else
		{
			// ERROR HANDLE
			luaL_error(L, "Invalid type. String expected");
			return 1;
		}
	}
	else
	{
		return 0;
	}
}
int CScriptInteraction::LuaPostVariable(lua_State *L)  
{
	int argc = lua_gettop(L);
	if(argc == 2)
	{
		if(lua_isstring(L, 2))
		{

			lua_pushstring(L, PostVariable(lua_tostring(L, 2)).c_str());
			return 1;
		}
		else
		{
			// ERROR HANDLE
			luaL_error(L, "Invalid type. String expected");
			return 1;
		}
	}
	else
	{
		return 0;
	}
}

int CScriptInteraction::Send(string Value)
{
	// Chunked Response
	if(!mResponseHeaders->HaveSent())
	{
		mResponseHeaders->SetResponseCode(200, "OK", mRequestInfo->mVersion);
		mClient->Send(mResponseHeaders->ToString());
	}
	stringstream sStream;

	int Length = Value.length();

	if(Length < 1)
	{
		return 0;
	}

	for (int i=2*sizeof(int) - 1; i>=0; i--) 
	{
		sStream << "0123456789ABCDEF"[((Length >> i*4) & 0xF)];
	}
	string Hex = sStream.str();
	Hex = Hex.substr(Hex.find_first_not_of("0")) + "\r\n";
	//mClient->Send(Hex.substr(Hex.find_first_not_of("0")) + "\r\n");
	int Return = mClient->Send(Hex + Value + "\r\n");
	if(Return == -1)
	{
		return -1;
	}
	return Return;
}

bool CScriptInteraction::Header(string Name, string Value)
{
	if(!mResponseHeaders->HaveSent())
	{
		(*mResponseHeaders) += pair<string, string>(Name, Value);
		return true;
	}
	else
	{
		return false;
	}
}

string CScriptInteraction::ServerVariable(string Name)
{
	for(auto it = mVariables.begin(); it != mVariables.end(); ++it)
	{
		if(it->first == Name)
		{
			return it->second;
		}
	}
	return "";
}

string CScriptInteraction::GetVariable(string Name)
{
	for(auto it = mGet.begin(); it != mGet.end(); ++it)
	{
		if(it->first == Name)
		{
			return it->second;
		}
	}
	return "";
}

string CScriptInteraction::PostVariable(string Name)
{
	for(auto it = mPost.begin(); it != mPost.end(); ++it)
	{
		if((*it).first.compare(Name) == 0)
		{
			return it->second;
		}
	}
	return "";
}